package com.atguigu.gmall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.cart.bean.CartInfo;
import com.atguigu.gmall.cart.bean.UserInfo;
import com.atguigu.gmall.cart.feign.PmsClient;
import com.atguigu.gmall.cart.feign.SmsClient;
import com.atguigu.gmall.cart.feign.WmsClient;
import com.atguigu.gmall.cart.interceptor.UserInfoInterceptor;
import com.atguigu.gmall.cart.service.CartAsyncService;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.pms.entity.SkuAttrValueEntity;
import com.atguigu.gmall.pms.entity.SkuEntity;
import com.atguigu.gmall.sms.vo.ItemSaleVo;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    PmsClient pmsClient;
    @Autowired
    WmsClient wmsClient;
    @Autowired
    SmsClient smsClient;
    @Autowired
    CartAsyncService cartAsyncService;
    //redis操作后 下一步操作需要查询数据 所有redis必须成功后才能执行下一步操作
    //数据库不影响下一步的查询 可以使用异步任务执行
    @Override
    public void add2Cart(String skuId, Integer count) {
        //1、获取用户的userId或者userKey
        String userId = UserInfoInterceptor.getUserId();
        //拼接该用户在redis中的购物车的key
        String cartKey = "cart:"+userId; //cartKey  skuId  cartInfo json
        //2、判断用户的购物车中是否存在skuId的购物项
        BoundHashOperations hashOps = redisTemplate.boundHashOps(cartKey);
        Boolean hasKey = hashOps.hasKey(skuId);
        CartInfo cartInfo  = new CartInfo();
        if(hasKey){
            //3、如果已经存在购物项，将数量+count
            cartInfo = (CartInfo) hashOps.get(skuId);//获取redis中的购物项
            cartInfo.setCount(cartInfo.getCount()+count);
            //更新数据库
            // UpdateWrapper: where后面的语句+ set后的语句
            //QueryWrapper:where后面的语句+ select后的语句
            //参数1：携带要更新的字段和值 如果为null忽略
            //参数2：查找要更新的行的条件
            cartAsyncService.updateCartInfo(userId,skuId,  cartInfo);
            //将cartInfo的数据存到redis的hash中
            hashOps.put(skuId , cartInfo);
        }else{
            //4、如果不存在 新建购物项保存到redis+mysql中
            cartInfo.setCount(count);
            cartInfo.setCheck(true);//默认选中
            cartInfo.setSkuId(skuId);
            cartInfo.setUserId(userId);
            //查询其他的数据
            //sku
            ResponseVo<SkuEntity> skuEntityResponseVo = pmsClient.querySkuById(Long.parseLong(skuId));
            SkuEntity skuEntity = skuEntityResponseVo.getData();
            if(skuEntity!=null){
                cartInfo.setDefaultImage(skuEntity.getDefaultImage());
                cartInfo.setPrice(skuEntity.getPrice());
                cartInfo.setTitle(skuEntity.getTitle());
                cartInfo.setCurrentPrice(skuEntity.getPrice());
                //设置skuId的价格到redis中：初始化实时价格
                redisTemplate.opsForValue().set("cart:current:"+skuId , skuEntity.getPrice());
            }
            //waresku
            ResponseVo<List<WareSkuEntity>> wareSkusResponseVo = wmsClient.queryWareSkusBySkuId(skuId);
            List<WareSkuEntity> wareSkuEntities = wareSkusResponseVo.getData();
            if(!CollectionUtils.isEmpty(wareSkuEntities)){
                cartInfo.setStore(wareSkuEntities.stream().anyMatch(wareSkuEntity ->
                        wareSkuEntity.getStock()-wareSkuEntity.getStockLocked()-count>=0));
            }
            //sms
            ResponseVo<List<ItemSaleVo>> itemSaleVosResponseVo = smsClient.querySalesBySkuId(skuId);
            List<ItemSaleVo> itemSaleVos = itemSaleVosResponseVo.getData();
            if(!CollectionUtils.isEmpty(itemSaleVos)){
                cartInfo.setSales(JSON.toJSONString(itemSaleVos));
            }
            //pms skuAttrValue
            ResponseVo<List<SkuAttrValueEntity>> skuSearchAttrValuesResponseVo = pmsClient.querySkuSearchAttrValues(Long.parseLong(skuId));
            List<SkuAttrValueEntity> skuAttrValueEntities = skuSearchAttrValuesResponseVo.getData();
            if(!CollectionUtils.isEmpty(skuAttrValueEntities)){
                cartInfo.setSaleAttrs(JSON.toJSONString(skuAttrValueEntities));
            }
            if(org.apache.commons.lang.StringUtils.isEmpty(UserInfoInterceptor.getUserInfo().getUserId())){
                cartInfo.setLogin(false);
            }else{
                //已登录
                cartInfo.setLogin(true);
            }
            //新增数据到数据库
            cartAsyncService.saveCartInfo(userId , cartInfo);
            //将cartInfo的数据存到redis的hash中
            //新增数据到购物车时 设置未登录购物项的过期时间
            hashOps.put(skuId , cartInfo);
            //userKey的购物车的过期时间如果为-1 设置过期时间
            Long expire = redisTemplate.getExpire(cartKey);
            System.out.println("expire = " + expire);
            if(StringUtils.isEmpty(UserInfoInterceptor.getUserInfo().getUserId())&&
                    expire==-1 ){
                redisTemplate.expire(cartKey , 30 , TimeUnit.DAYS);//和userKey在客户端缓存的过期时间一样
            }

        }


    }



    @Override
    public CartInfo queryCartInfoBySkuId(String skuId) {
        //获取当前用户的购物车
        String userId = UserInfoInterceptor.getUserId();
        BoundHashOperations hashOps = redisTemplate.boundHashOps("cart:" + userId);
        //根据skuId查询cartInfo数据
        return (CartInfo) hashOps.get(skuId);
    }
    //需要判断是否登录：需要考虑未登录和已登录购物车的合并
    @Override
    public List<CartInfo> queryCarts() {
        UserInfo userInfo = UserInfoInterceptor.getUserInfo();
        String userKey = userInfo.getUserKey();
        //1、先查询未登录购物车
        BoundHashOperations ops1 = redisTemplate.boundHashOps("cart:" + userKey);
        List<CartInfo> unloginCarts = ops1.values();
        //2、判断如果未登录直接返回未登录购物车
        String userId = userInfo.getUserId();
        if(StringUtils.isEmpty(userId)){
            //如果查询到的redis中的购物车数据为空 查询数据库未登录的购物车数据
            if(CollectionUtils.isEmpty(unloginCarts)){
                unloginCarts = cartAsyncService.queryCartsByUserId(userKey);
                //如果非空同步数据到redis
                if(!CollectionUtils.isEmpty(unloginCarts)){
                    //redis中的购物车数据丢失  同步数据库的购物车数据到redis中
                    unloginCarts.forEach(cartInfo -> {
                        ops1.put(cartInfo.getSkuId() ,cartInfo);
                    });
                }
            }
            //返回未登录购物车前 设置所有购物项的实时价格
            unloginCarts.forEach(cartInfo -> {
                if(redisTemplate.hasKey("cart:current:"+cartInfo.getSkuId())){
                    BigDecimal currenPrice = (BigDecimal) redisTemplate.opsForValue().get("cart:current:" + cartInfo.getSkuId());
                    cartInfo.setCurrentPrice(currenPrice);
                }
            });
            return unloginCarts;
        }
        //3、已登录查询已登录购物车
        BoundHashOperations ops2 = redisTemplate.boundHashOps("cart:" + userId);
        //如果从redis获取的已登录购物车为空 查询数据库的已登录购物车同步到redis中
        if(ops2.size()==0){
            List<CartInfo> cartInfos = cartAsyncService.queryCartsByUserId(userId);
            if(!CollectionUtils.isEmpty(cartInfos)){
                cartInfos.forEach(cartInfo -> {
                    ops2.put(cartInfo.getSkuId() , cartInfo);
                });
            }
        }
        //4、如果未登录购物车不为空 遍历未登录购物车合并到已登录的购物车中
        if(!CollectionUtils.isEmpty(unloginCarts)){
            unloginCarts.forEach(unloginCart->{
                CartInfo cartInfo ;
//                ops2 :  skuId   cartInfo
                if(ops2.hasKey(unloginCart.getSkuId())){
                     // 已存在合并count
                    cartInfo = (CartInfo) ops2.get(unloginCart.getSkuId());
                    cartInfo.setCount(cartInfo.getCount()+ unloginCart.getCount());
                    //更新redis中的数据
                    //更新数据库购物项
                    cartAsyncService.updateCartInfo(userId,unloginCart.getSkuId(),cartInfo);
                }else{
                    //不存在将购物项添加到已登录购物车
                   // unloginCart.setUserId(userId);//将购物项的用户id设置为登录的id
                    cartInfo = new CartInfo();
                    BeanUtils.copyProperties(unloginCart,cartInfo);
                    cartInfo.setUserId(userId);
                    //保存数据到数据库
                    //新增购物项 如果用户未登录  设置is_login状态为false
                    if(org.apache.commons.lang.StringUtils.isEmpty(UserInfoInterceptor.getUserInfo().getUserId())){
                        cartInfo.setLogin(false);
                    }else{
                        //已登录
                        cartInfo.setLogin(true);
                    }
                    cartAsyncService.saveCartInfo(userId,cartInfo);
                }
                ops2.put(unloginCart.getSkuId() , cartInfo);
            });
            //5、删除redis未登录的购物车
            redisTemplate.delete("cart:"+userKey);
            //删除数据库未登录购物车
            cartAsyncService.deleteCarts(unloginCarts);
        }
        //6、返回已登录的购物车集合:已登录和未登录购物车合并完毕
        List<CartInfo> cartInfos = ops2.values();

        //从redis中查询数据
        //获取userId/userKey
        //获取该用户在redis中的购物项集合
//        String userId = UserInfoInterceptor.getUserId();
//        BoundHashOperations ops = redisTemplate.boundHashOps("cart:" + userId);
//        ops.keys();  购物车中的购物项对应的sku的id集合
//        ops.values() 购物车中的购物项集合

        // //返回登录购物车前 设置所有购物项的实时价格
        cartInfos.forEach(cartInfo -> {
            if(redisTemplate.hasKey("cart:current:"+cartInfo.getSkuId())){
                BigDecimal currenPrice = (BigDecimal) redisTemplate.opsForValue().get("cart:current:" + cartInfo.getSkuId());
                cartInfo.setCurrentPrice(currenPrice);
            }
        });
        return cartInfos;
    }
    @Async
    public String exec1(){
        try {
            Thread.sleep(1000);
            System.out.println("exec1执行结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return "exec1";
    }
    @Async
    public String exec2(){
        try {
            Thread.sleep(3000);
            int i = 1/0;
            System.out.println("exec2执行结束...");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return "exec2";
    }

    @Override
    public Boolean updateCartInfoNum(CartInfo cartInfo) {
        //更新购物项的数量
        //1、查询购物项
        String skuId = cartInfo.getSkuId();
        String userId = UserInfoInterceptor.getUserId();
        BoundHashOperations ops = redisTemplate.boundHashOps("cart:" + userId);
        CartInfo cartInfo2 = (CartInfo) ops.get(skuId);
        if(cartInfo2!=null && cartInfo.getCount()>0){
            cartInfo2.setCount(cartInfo.getCount());
            //更新到redis中
            ops.put(skuId , cartInfo2);
            //更新到数据库中
            cartAsyncService.updateCartInfo(userId,skuId,cartInfo2);
            return true;
        }
        return false;
    }

    @Override
    public Boolean deleteCartInfo(String skuId) {
        String userId = UserInfoInterceptor.getUserId();
        BoundHashOperations ops = redisTemplate.boundHashOps("cart:" + userId);
        Long delete = ops.delete(skuId); //返回删除的记录条数
        cartAsyncService.deleteCartInfoByUserIdAndSkuId(userId,skuId);

        return delete>0;
    }

    @Override
    public Boolean updateCartInfoStatus(CartInfo cartInfo) {
        String userId = UserInfoInterceptor.getUserId();
        BoundHashOperations ops = redisTemplate.boundHashOps("cart:" + userId);
        CartInfo cartInfo2 = (CartInfo) ops.get(cartInfo.getSkuId());
        if(cartInfo2!=null){
            cartInfo2.setCheck(cartInfo.getCheck());
            ops.put(cartInfo.getSkuId() , cartInfo2);
            cartAsyncService.updateCartInfo(userId ,cartInfo.getSkuId(), cartInfo2);
            return true;
        }

        return false;
    }

    @Override
    public void batchupdateCartInfoStatus(List<String> skuIds, Boolean status) {
        String userId = UserInfoInterceptor.getUserId();
        BoundHashOperations ops = redisTemplate.boundHashOps("cart:" + userId);
        List<CartInfo> cartInfos = ops.values();
        if(!CollectionUtils.isEmpty(cartInfos)){
            cartInfos.forEach(cartInfo -> {
                if(skuIds.contains(cartInfo.getSkuId())){
                    //sku的状态需要修改
                    cartInfo.setCheck(status);
                    ops.put(cartInfo.getSkuId() , cartInfo);
                    cartAsyncService.updateCartInfo(userId,cartInfo.getSkuId(),cartInfo);
                }
            });

        }

    }

    @Override
    public List<CartInfo> queryCheckedCarts(String userId) {
        //查询用户的购物车
        //常量 一定不会改   配置：可能修改
        BoundHashOperations ops = redisTemplate.boundHashOps("cart:" + userId);
        if(ops.size()==0){
            return null;
        }
        List<CartInfo> cartInfos = ops.values();
        //筛选已选中的购物项
        cartInfos = cartInfos.stream().filter(cartInfo -> cartInfo.getCheck())
                .collect(Collectors.toList());
        return cartInfos;
    }
//    @Async
//    public ListenableFuture<String> exec1(){
//        try {
//            Thread.sleep(1000);
//            System.out.println("exec1执行结束...");
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        return AsyncResult.forValue("exec1");
//    }
//    @Async
//    public ListenableFuture<String> exec2(){
//        try {
//            Thread.sleep(3000);
//            int i = 1/0;
//            System.out.println("exec2执行结束...");
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//            return AsyncResult.forExecutionException(e);
//        }
//        return AsyncResult.forValue("exec2");
//    }
}
